from lexical import openFile, closeFile, getToken
from entity.tool import getTerm, symTranMap


# 读取文法，返回 序号-(规约生成符号,符号长度) 字典
def readGram(filename='../resources/setGrammar.txt'):
    graMap = {}
    order = 0

    with open(filename, 'r') as f:
        for gra in f.readlines():
            # 读取并分割左和右
            curGra = gra.replace('\n', '').replace(' ', '').replace('<', '<').replace('\t', '').split('→')
            length = 0
            # 右边
            right = curGra[1]
            # 遍历右边每一个符号
            while len(right) > 0:
                # 如果是非终结符
                if right[0] != '<':
                    # print(right)
                    # 读取一个终结符
                    term = getTerm(right)
                    length += 1
                    right = right[len(term):]
                else:
                    pos = right.find('>')
                    length += 1
                    right = right[pos + 1:]

            graMap[str(order)] = (curGra[0], length)
            order += 1
    return graMap


# 读取下推自动机
def readMachine(filename='../outputs/moveTable.csv'):
    move = {}
    with open(filename, 'r') as f:
        # 首先读入标题
        titles = f.readline().replace('\n', '').split(',')[1:]
        # .replace('逗号',',')
        for i in range(len(titles)):
            if titles[i] == '逗号':
                titles[i] = ','

        # 读取每一行
        for l in f.readlines():
            l = l.replace('\n', '').split(',')
            move[l[0]] = {}
            for i in range(len(titles)):
                # 设置文字
                move[l[0]][titles[i]] = l[i + 1]
    return move


# 分析代码，返回语法树
def analyseCode(readFilename='../resources/test.grammar', writeFilename='../outputs/syntacticAnalysis.txt'):
    print('正在进行文法分析...')

    # 读取下推自动机
    move = readMachine()
    # 读取文法
    gram = readGram()
    # 状态栈，初始状态下状态0进栈
    statusStack = ['0']
    # 符号栈
    symbleStack = []

    # 树根-树映射
    rootTreeMap = {}

    rf = openFile(readFilename)
    tok = 'empty'
    with open(writeFilename, 'w') as wf:
        while tok[0] != 35:
            if tok == 'empty':
                tok = getToken()
            # 获取下推自动机的表示方式
            sym = symTranMap[tok[0]]
            # 得到状态-符号对应的动作
            action = move[statusStack[-1]][sym]
            wf.writelines('当前action为%s\n' % action)

            # 如果是移进
            if action[0] == 's':
                wf.write('操作: 移进\n')
                # 推入状态栈
                statusStack.append(action[1:])
                # 推入符号栈
                symbleStack.append(sym)
                wf.write('移进后状态栈为%s\n' % statusStack)
                wf.write('移进后符号栈为%s\n\n' % symbleStack)
                # 清空
                tok = 'empty'

            # 如果是规约
            elif action[0] == 'r':
                wf.write('操作: 进入规约\n')
                # 获取文法序号
                garNum = action[1:]
                # 获取文法
                gra = gram[garNum]
                wf.write('规约前状态栈为%s\n' % statusStack)
                wf.write('规约前符号栈为%s\n' % symbleStack)
                wf.write('当前文法为%s 长度为%s\n' % (gra[0], gra[1]))

                symbs = []
                # 弹栈
                for i in range(gra[1]):
                    statusStack.pop()  # = statusStack[:-1]
                    symb = symbleStack.pop()  # = symbleStack[:-1]
                    symbs.append(symb)
                rootTreeMap[gra[0]] = symbs

                symbleStack.append(gra[0])
                statusStack.append(move[statusStack[-1]][symbleStack[-1]])
                # symbleStack.append(sym)
                wf.write('规约后状态栈为%s\n' % statusStack)
                wf.write('规约后符号栈为%s\n\n' % symbleStack)

            else:
                wf.write('出现错误！出错位置为第%d行\n' % tok[3])
                print('出现错误！出错位置为第%d行\n' % tok[3])
                return
        wf.write('\n语法分析完成，语法分析器未检测出错误！\n')
    closeFile(readFilename)
    print('语法分析完成，请查看output/syntacticAnalysis.txt文件\n')
    return rootTreeMap


if __name__ == '__main__':
    treeNodes = analyseCode()
